package com.hospital.gateway.module.filter;

import com.hospital.auth.module.utils.RedisUtils;
import com.hospital.common.utils.JwtUtils;
import com.hospital.common.utils.LogUtils;
import com.hospital.gateway.module.config.WhiteListConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Map;

import static com.hospital.common.base.interfaces.Const.*;

@Order(0)
@Component
public class GatewayFilter implements GlobalFilter {
    @Autowired
    private WhiteListConfig whiteListConfig;
    @Autowired
    private RedisUtils redisUtils;
    private static final String AUTHORIZATION = "Authorization";
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        LogUtils.info("进入网关过滤器");
        ServerHttpRequest request =  exchange.getRequest();
        // 白名单
        for(String path:whiteListConfig.getWhitelist()){
            if(request.getPath().value().contains(path)){
                return chain.filter(exchange);
            }
        }
        // 微服务内部调用时跳过鉴权
        String internalCall = request.getHeaders().getFirst(INTERNAL_CALL_HEADER);
        if(!ObjectUtils.isEmpty(internalCall)){
            if(internalCall.equals(INTERNAL_CALL_VALUE)){
                return chain.filter(exchange);
            }
        }
        // 进行token验证
        String token = request.getHeaders().getFirst(AUTHORIZATION);
        if(ObjectUtils.isEmpty(token)){
            // 如果为websocket请求,判断是否携带token
            token = request.getHeaders().getFirst(SEC_WEBSOCKET_PROTOCOL);
            if(ObjectUtils.isEmpty(token)){
                return errorHandler(exchange.getResponse());
            }
        }
        if(!redisUtils.hasKey(SESSION_KEY_PREFIX+token)){
            // 验证token失败
            return errorHandler(exchange.getResponse());
        }
        Map<String,Object> payload = validateToken(token);
        if(ObjectUtils.isEmpty(payload)){
            // 验证token失败
            return errorHandler(exchange.getResponse());
        }
        if(!payload.containsKey(USER_ID_HEADER)){
            return errorHandler(exchange.getResponse());
        }
        if(!payload.containsKey(ROLE_TYPE_HEADER)){
            return errorHandler(exchange.getResponse());
        }
        // 设置用户ID和角色类型到请求头中
        request = request.mutate()
                .header(USER_ID_HEADER, payload.get(USER_ID_HEADER).toString())
                .header(ROLE_TYPE_HEADER, payload.get(ROLE_TYPE_HEADER).toString())
                .build();
        ServerWebExchange newExchange = exchange.mutate().request(request).build();
        return chain.filter(newExchange);
    }
    public Mono<Void> errorHandler(ServerHttpResponse response){
        response.setStatusCode(HttpStatus.FORBIDDEN); // 设置为 403
        // 构造返回内容
        String body = "{\"code\":403,\"message\":\"Forbidden: Token missing or invalid\"}";
        byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bytes);
        // 设置响应头
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(buffer));
    }
    private Map<String, Object> validateToken(String token){
        return JwtUtils.validateToken(token);
    }
}
